package com.hxzy.controller.mobile.alipay;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hxzy.common.constants.MarketConstants;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.exception.ServiceException;
import com.hxzy.entity.Merchandiser;
import com.hxzy.entity.Orders;
import com.hxzy.service.MerchandiserService;
import com.hxzy.service.OrdersService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.ServerException;
import java.util.*;

@Log4j2
@RequestMapping(value = "/mobile/alipay")
@RestController
@Api(tags = "手机-支付宝支付API")
public class AlipayController {

    @Autowired
    private OrdersService ordersService;

    @Autowired
    private MerchandiserService merchandiserService;

    @ApiOperation(value = "向支付宝发起支付申请")
    @GetMapping(value = "/{orderNumber}")
    public void paymentApplication(@PathVariable(value = "orderNumber") String orderNumber, HttpServletResponse response) throws AlipayApiException, IOException {
        if(StrUtil.isBlank(orderNumber)){
            throw new ServiceException(AckCode.PAY_ORDERID_NOT_NULL);
        }

        Orders  db=this.ordersService.getByOrderNumber(orderNumber);
        if(Objects.isNull(db)){
            throw new ServiceException(AckCode.NOT_FOUND_DATA);
        }

        //支付状态不是未支付
        if(!db.getStatus().equals(MarketConstants.ACCOUT_DISABLE)){
            throw new ServiceException(AckCode.PAY_ORDER_STATE_ERROR);
        }

        //更新订单表，第一次发起支付的时间
        if(Objects.isNull(db.getCheckoutTime())){
            //设定一个时间，让我们清楚，已经向支付宝发送起支付请求
            Orders  entity=new Orders();
            entity.setId(db.getId());
            entity.setCheckoutTime(new Date());
            boolean result=this.ordersService.updateById(entity);
            if(result){
                //调用支付宝的api，发起请求
                this.paymentWriteForm(db,response);

            }else{
                throw new ServiceException(AckCode.PAY_ORDER_START_ERROR);
            }

        }else{
            //之前发送过，现在还不清楚订单在支付宝的状态是什么？
            //只向向支付宝发起对账申请
            alipaySearch(db,response);
        }
    }

    /**
     * 支付宝对账查询(由于某种原因，向支付宝发送支付请求，但是值有问题)
     * @param db
     * @param response
     */
    private void alipaySearch(Orders db, HttpServletResponse response) throws AlipayApiException, IOException {
        com.alipay.api.AlipayConfig alipayConfig = MyAlipayConfig.getAlipayConfig();

        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);

        //交易查询请求
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

        //交易请求参数
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        //传入订单号
        model.setOutTradeNo(db.getNumber());

        request.setBizModel(model);

        //查询对账号结果
        AlipayTradeQueryResponse resp = alipayClient.execute(request);

        /*
         {
            "alipay_trade_query_response": {
              "code": "10000",
              "msg": "Success",
              "buyer_logon_id": "imv***@sandbox.com",
              "buyer_pay_amount": "0.00",
              "buyer_user_id": "2088722016300001",
              "buyer_user_type": "PRIVATE",
              "invoice_amount": "0.00",
              "out_trade_no": "1710574398805708800000003",
              "point_amount": "0.00",
              "receipt_amount": "0.00",
              "send_pay_date": "2023-10-08 14:32:54",
              "total_amount": "21.00",
              "trade_no": "2023100822001400000500944853",
              "trade_status": "TRADE_SUCCESS"
            },
            "sign": "LdSvPqPbTV3uOSftUqh2bsAhSTUrSFbNoo+W3q2lo778NzgA7a1wRWd48QBqO35+Im+hjMLiIm0+NzGX9HM2B8VbTiRR6bloLGllz0mErgwIbZiPQw/YZDTWL73lpiZDlBRJv5JO0+6JxLFRNtJqXuO35SWl6NszwdEHcPKe+Qkk49m1bhR9wVdxS8CzSpkLSDI2wvmZ9dlWSTOzOEH6fdNiWmoc03ct92UBEuGQTVDjpQ28lw8iVTiGvOl2L+MrxbJ3ljmYA368uoP8YaTA/vq7jEJ2p9TvCtDCbsYe1BDEILC5lYOq4VNuBZiXTAPAOlQSuYGx3l8wEp54pFgsyw=="
          }
         */

        String msg="";
        log.info( resp.getBody());
        //已经交易过了,支付已经收到钱了
        if("10000".equals(resp.getCode())) {
            //更新数据库订单状态
            //客户实际支付金额
            String totalAmout=resp.getTotalAmount();
            //我们自己订单号
            String outTradeNo = resp.getOutTradeNo();
            //支付宝交易号
            String alipayTradeNo = resp.getTradeNo();

            Date payDate = resp.getSendPayDate();

            boolean result=this.ordersService.updatePayStatusByOrderId( db.getNumber() ,payDate,new BigDecimal(totalAmout),alipayTradeNo);
            //给前端输出已经支付过，不允许再支付了
            msg="订单已支付过，不允许再提交了";
            outInfo(response,msg);

        }else if("40004".equals(resp.getCode())) {
            //没有支付过，再次发送支付请求
            paymentWriteForm(db, response);
        }else{
            //错误消息
            msg= resp.getMsg();
            log.error(resp.getBody());

            //我们自己订单号
            String outTradeNo = resp.getOutTradeNo();
            //取消订单
            this.ordersService.cancelCheckOutTime(outTradeNo);
            //记录到表中，供管理员查看
            outInfo(response,msg);
        }

    }


    private void outInfo(HttpServletResponse response,String message) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out= response.getWriter();
        String str="<script>\n" +
                "   alert('"+message+"');\n" +
                "   window.location.href='https://310y57x926.yicp.fun';\n" +
                "</script>";
        out.write(str);
        out.flush();
        out.close();
    }


    /**
     * 向支付SDK申请发送订单，返回的html字符串
     * @param orders
     * @param response
     */
    private void paymentWriteForm(Orders orders,HttpServletResponse response) throws AlipayApiException, IOException {


        //调用支付宝SDK程序
        AlipayClient alipayClient = new DefaultAlipayClient(MyAlipayConfig.getAlipayConfig());

        //创建一个请求
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

        //支付宝SDK请求参数
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(orders.getNumber());
        //金额保留小数2位
        //商品总价格（精确到小数点后两位） ecimal.setScale(2,BigDecimal.ROUND_HALF_UP)
        BigDecimal bigDecimal = orders.getAmount().setScale(2, RoundingMode.UP);
        model.setTotalAmount( bigDecimal.floatValue()+"");


        //查询商家名称
        LambdaQueryWrapper<Merchandiser> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(Merchandiser::getId,orders.getMerchantId());
        queryWrapper.select(Merchandiser::getName);
        Merchandiser merchandiser = this.merchandiserService.getOne(queryWrapper);

        //商家店铺
        String subject="向"+merchandiser.getName()+"付款";
        model.setSubject(subject);

        model.setProductCode("QUICK_WAP_WAY");
        request.setBizModel(model);

        //设定请求的异步回调地址，这个地址，必须与支付宝配置的 授权回调地址 一模一样
        request.setNotifyUrl(MyAlipayConfig.notify_url);

        //请求网站跳转的地址
        request.setReturnUrl(MyAlipayConfig.return_url);

        AlipayTradeWapPayResponse tradeWapPayResponse = alipayClient.pageExecute(request, "POST");
        // 如果需要返回GET请求，请使用
        // AlipayTradeWapPayResponse response = alipayClient.pageExecute(request, "GET");
        //支付宝生成的html的form表单字符串
        String pageRedirectionData = tradeWapPayResponse.getBody();
        log.info(pageRedirectionData);

        if (tradeWapPayResponse.isSuccess()) {

            response.setContentType("text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            PrintWriter out=response.getWriter();
            out.println(pageRedirectionData);
            out.flush();
            out.close();
        } else {
            log.error("向支付宝发起支付申请失败：原因是");
            log.error(tradeWapPayResponse.toString());
            throw new ServiceException(AckCode.PAY_ORDER_START_ERROR);
        }
    }




    /**
     * 支付宝服务器支付以后的回调通知地址
     * @return
     */
    @RequestMapping(value = "/notify")
    public void alipayCallbackNotify(HttpServletRequest request,HttpServletResponse response) throws IOException, AlipayApiException {
        System.out.println("=========支付宝异步回调========");

        request.setCharacterEncoding("UTF-8");
        PrintWriter out=response.getWriter();

        Map<String, String> params = new HashMap<>();

        //获取支付宝返回的参数
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            params.put(name, request.getParameter(name));
        }

        log.info(requestParams.toString());

        if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {

            //拿到内容，再一次加密与支付宝返回的sign进行比较，如果正确，支付没有问题的(数据没有修改过)
            boolean verify_result = AlipaySignature.rsaCheckV1(params, MyAlipayConfig.ALIPAY_PUBLIC_KEY, MyAlipayConfig.CHARSET, "RSA2");
            // 支付宝验签
            if (verify_result) {
                // 验签通过
                System.out.println("交易名称: " + params.get("subject"));
                System.out.println("交易状态: " + params.get("trade_status"));
                System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
                System.out.println("商户订单号: " + params.get("out_trade_no"));
                System.out.println("交易金额: " + params.get("total_amount"));
                System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
                System.out.println("买家付款时间: " + params.get("gmt_payment"));
                System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));

                String orderNumber= params.get("out_trade_no");
                String payTime=params.get("gmt_payment");
                String buyerAmount=params.get("buyer_pay_amount");
                // 更新订单表  支付状态 以及支付方式  checkout_time
                Date payDate= DateUtil.parse(payTime,"yyyy-MM-dd HH:mm:ss");

                //我们自己订单号
                String outTradeNo = params.get("out_trade_no");
                //客户实际支付金额
                String gmtPayment = params.get("gmt_payment");
                //支付宝交易号
                String alipayTradeNo = params.get("trade_no");
                // 得到 参数签名 (支付宝根据你的参数使用RSA非对称加密生成的串值)
                String sign = params.get("sign");

                boolean result=this.ordersService.updatePayStatusByOrderId( orderNumber ,payDate,new BigDecimal(buyerAmount),alipayTradeNo);
                if(!result){
                    //记录日志，记录redis中，支付成功，但是你更新数据库失败的
                    String json= JSONUtil.toJsonStr(params);
                    log.error(json+",支付成功，但更新数据库失败");
                    out.println("fail");
                }else{
                    out.println("success");
                }
            }else{
                log.error(AckCode.ORDER_PAY_CheckSignature.getMsg());
                out.println("fail");
            }
        }else{
            log.error(AckCode.ORDER_PAY_FAIL.getMsg());
            out.println("fail");
        }
    }


}
